package com.zimmur.controller;

import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.csource.common.NameValuePair;
import org.csource.fastdfs.StorageClient;
import org.csource.fastdfs.StorageServer;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import com.zimmur.common.AppModuleEnum;
import com.zimmur.common.ConstData;
import com.zimmur.common.IDWorkFactory;
import com.zimmur.common.ReturnJsonEntity;
import com.zimmur.common.StatusCodeEnum;
import com.zimmur.model.fdfs.FastDFSFile;
import com.zimmur.model.fdfs.StorageFiles;
import com.zimmur.service.fdfs.IStorageFilesService;
import com.zimmur.tenpay.util.MD5;
import com.zimmur.tools.DateUtils;
import com.zimmur.tools.FileContentTypeUtil;
import com.zimmur.tools.ImageMagick;

@Controller
@RequestMapping("/restful/file")
public class UserFileController extends BaseController{
	private static Logger logger=LoggerFactory.getLogger(UserFileController.class);
	//private static String URI_SEPARATOR="/";
	
	@Resource(name = "trackerClient")
	private TrackerClient trackerClient;
	
	@Resource
	private IStorageFilesService storageFilesService;
	
	private static String AUTHOR = "author";	
	private static String FILE_NAME = "fileName";
	
	private static Object syncObj=new Object();
	private static Object syncLocalObj = new Object();
	
	@ResponseBody
	@RequestMapping("/upload")
	public ReturnJsonEntity upload(@RequestParam(value="files", required=true) MultipartFile[] files){
		ReturnJsonEntity entity = new ReturnJsonEntity();
		StatusCodeEnum statusCodeEnum=StatusCodeEnum.CODE100000;
		try {
			if(files.length == 0){
				entity.setMsg("upload.resources.empty");
			}else{
				List<FastDFSFile> fileList = new ArrayList<FastDFSFile>();
				for (MultipartFile partFile : files) {
					FastDFSFile file = null;
					try {
						if(!partFile.isEmpty()){
							file = new FastDFSFile(partFile.getOriginalFilename(), partFile.getBytes(),
									StringUtils.getFilenameExtension(partFile.getOriginalFilename()));
							file.setSize(partFile.getSize());
							fileList.add(file);
						}					
					} catch (Exception e) {
						logger.error(e.getMessage());
					}			
				}
				if(files.length == fileList.size()){
					long userId=getTokenUserId();
					try{
						if(mulityFileSaveFdfs(fileList,String.valueOf(userId))){
							entity.setData(fileList);
							statusCodeEnum=StatusCodeEnum.CODE000000;
						}						
					}catch(Exception er){
						logger.error(er.getMessage());
					}
					
				}
			}
			
		} catch (Exception e) {
			statusCodeEnum=StatusCodeEnum.CODE100000;
			entity.setData(new ArrayList<>());
		}
		entity.setCode(statusCodeEnum.getCode());
		entity.setMsg(statusCodeEnum.getMsg());
		
		return entity;
		
	}
	@ResponseBody
	@RequestMapping(value="/download",method=RequestMethod.GET)
	public void downloadFile(HttpServletRequest request,HttpServletResponse response,@RequestParam(value="fileId",required=true)long fileId){
		
		BufferedInputStream bis = null;
		BufferedOutputStream bos = null;
		try {
			response.setContentType("text/html;charset=UTF-8");  
	        request.setCharacterEncoding("UTF-8"); 
	        
			StorageFiles storageFile = getStorageFile(fileId);
			if(storageFile != null){
				long fileLength = storageFile.getFilesize();  
		        response.setContentType(FileContentTypeUtil.getcontentType(storageFile.getFileext()));  
		        response.setHeader("Content-disposition", "attachment; filename="  
		                + new String(storageFile.getOriginalfilename().getBytes("utf-8"), "ISO8859-1"));  
		        response.setHeader("Content-Length", String.valueOf(fileLength));  
		        InputStream sbs = new ByteArrayInputStream(downloadFdfsFile(storageFile.getStoragegroup(),storageFile.getStorageid()));
		        
		        bis = new BufferedInputStream(sbs);  
		        bos = new BufferedOutputStream(response.getOutputStream());  
		        byte[] buff = new byte[2048];  
		        int bytesRead;  
		        while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {  
		            bos.write(buff, 0, bytesRead);  
		        }  
		        sbs.close();
			}
			
		} catch (Exception e) {
		}finally{
			 try {
				 if(bis != null)
					 bis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}  
		     try {
		    	 if(bos != null)
		    		 bos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}  
		}
        
	}
	@ResponseBody
	@RequestMapping(value="/downloadthumb",method=RequestMethod.GET)
	public void downloadFileForSize(@RequestParam(value="fileId",required=true)long fileId){
		HttpServletResponse  response = getResponse();
		HttpServletRequest request = getRequest();
		
		BufferedInputStream bis = null;
		BufferedOutputStream bos = null;
		try {
			response.setContentType("text/html;charset=UTF-8");  
	        request.setCharacterEncoding("UTF-8"); 
	        
			StorageFiles storageFile = getStorageFile(fileId);
			if (storageFile != null) {
				long fileLength = storageFile.getFilesize();
				int width = getIntParam("w");
				int height = getIntParam("h");
				response.setContentType(FileContentTypeUtil.getcontentType(storageFile.getFileext()));
				response.setHeader("Content-disposition", "attachment; filename="
						+ new String(storageFile.getOriginalfilename().getBytes("utf-8"), "ISO8859-1"));
				
				InputStream sbs = null;
				
				if (width > 0 || height > 0) {
					if(width>0)
						width = (int)(width * 1.5);
					if(height > 0){
						height = (int)(height * 1.5);
					}
					String fileFullName;
					fileFullName = checkExistsFile(storageFile.getStoragegroup(), storageFile.getStorageid(),
							storageFile.getFileext(), width, height);
					if (fileFullName == null) {
						byte[] fileData = downloadFdfsFile(storageFile.getStoragegroup(), storageFile.getStorageid());
						if(saveThumbImage(storageFile.getStoragegroup(), storageFile.getStorageid(),
								storageFile.getFileext(), width, height, fileData)){
							fileFullName = checkExistsFile(storageFile.getStoragegroup(), storageFile.getStorageid(),
									storageFile.getFileext(), width, height);
						}	
						fileData = null;
					}
					downloadLocal(response, fileFullName,storageFile.getFileext());
					return;
					
				} else {
					response.setHeader("Content-Length", String.valueOf(fileLength));
					sbs = new ByteArrayInputStream(
							downloadFdfsFile(storageFile.getStoragegroup(), storageFile.getStorageid()));
					bis = new BufferedInputStream(sbs);
					bos = new BufferedOutputStream(response.getOutputStream());
					byte[] buff = new byte[2048];
					int bytesRead;
					while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
						bos.write(buff, 0, bytesRead);
					}
					bos.flush();
					sbs.close();
				}
				
			}
			
		} catch (Exception e) {
			logger.error(e.getMessage());
		}finally{
			 try {
				 if(bis != null)
					 bis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}  
		     try {
		    	 if(bos != null)
		    		 bos.close();
			} catch (IOException e) {
				e.printStackTrace();
			} 
		     
		}
        
	}
	public void downloadLocal(HttpServletResponse response,String fileName,String fileExt) throws FileNotFoundException {
		OutputStream toClient = null;
		InputStream fis = null;
		try {
			synchronized (syncLocalObj) {
				// path是指欲下载的文件的路径。
	            File file = new File(fileName);
	            if(!file.exists()){
	            	return;
	            }
	            // 取得文件名。
	            String filename = file.getName();
	            // 取得文件的后缀名。
//	            String ext = filename.substring(filename.lastIndexOf(".") + 1).toUpperCase();

	            // 以流的形式下载文件。
	            fis = new BufferedInputStream(new FileInputStream(fileName));
	            byte[] buffer = new byte[fis.available()];
	            fis.read(buffer);
	            fis.close();
	            // 清空response
//	            response.reset();
	            // 设置response的Header
	            response.addHeader("Content-Length", "" + file.length());
	            toClient = new BufferedOutputStream(response.getOutputStream());
	            toClient.write(buffer);
	            toClient.flush();
			}
            
        } catch (IOException ex) {
            ex.printStackTrace();
        }
		finally{
			if(fis != null){
				try {
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(toClient != null){
				try {
					toClient.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
				
		}
    }
	/**
	 * 检查本地文件是否存在
	 * @param groupName
	 * @param storageId
	 * @param fileExt
	 * @param width
	 * @param height
	 * @return
	 */
	private String checkExistsFile(String groupName,String storageId,String fileExt,int width,int height){
		//获取我项目中存储图片的文件夹地址 你要换成你自己的目录
        String imageFold = getRequest().getServletContext().getRealPath("/thumbimages");
        File fold = new File(imageFold);
        if (!fold.exists()) {
            fold.mkdir();
        }
        String fileName = MD5.MD5Encode(storageId)+"_"+width+"x"+height+"."+fileExt;
        String fullFileName = imageFold+File.separator+fileName;
        File fileInfo = new File(fullFileName);
        if(fileInfo.exists()){
        	return fullFileName;
        }
        return null;
	}
	
	private boolean saveThumbImage(String groupName,String storageId,String fileExt,int width,int height,byte[] data){
		String imageFold = getRequest().getServletContext().getRealPath("/thumbimages");
        File fold = new File(imageFold);
        if (!fold.exists()) {
            fold.mkdir();
        }
        String fileName = MD5.MD5Encode(storageId)+"_"+width+"x"+height;
        String fullFileName = imageFold+File.separator+fileName+"_middle"+"."+fileExt;
        String destFileName = imageFold+File.separator+fileName+"."+fileExt;
        File fileInfo = new File(destFileName);
        if(!fileInfo.exists()){
        	synchronized (syncObj) {
        		String tempFileName = imageFold+File.separator+fileName+"_test."+fileExt;
            	File fileTemp = new File(tempFileName);
            	if(!fileTemp.exists()){
            		ImageMagick.byte2Image(data, tempFileName);
            		data = null;
            	}
            	InputStream is =null;
            	BufferedImage buff = null;
            	try {
            		if(fileTemp.exists()){
            			// 通过文件名称读取
            			is = new FileInputStream(tempFileName);
            			buff = ImageIO.read(is);
            			int srcWidth = buff.getWidth();// 得到图片的宽度
            			int srcHeight = buff.getHeight();// 得到图片的高度
            			is.close(); // 关闭Stream
            			
            			//ImageMagick.cutImage(width, height, tempFileName, fullFileName, 1, "80");
            			//1、指定宽，高自适应，等比例缩放;
            			//2、指定高， 宽自适应，等比例缩放;
            			//3、指定最长边，短边自适应，等比例缩放; 
            			//4、指定最短边，长边自适应，等比例缩放; 
            			//5、指定最大宽高， 等比例缩放;	 
            			//6、固定宽高， 居中裁剪）
            			int mode=1;
            			if(width>0 && height>0){
            				if(srcWidth>srcHeight){
            					mode = 2;
            				}else{
            					mode = 1;
            				}
            			}else if(width>0){
            				mode = 1;
            			}else if(height>0){
            				mode = 2;
            			}
            			ImageMagick imageMagick = new ImageMagick();
            			imageMagick.resize(mode, tempFileName, fullFileName,destFileName, width, height, 0, 0, "85");
    					fileTemp.delete();
    				}
    				return true;
    			} catch (Exception e) {
    				logger.error(e.getMessage());
    			}finally{
    				if(buff !=null){
    					buff = null;
    				}
    				if(is!=null){
    					try {
							is.close();
						} catch (IOException e) {
							e.printStackTrace();
						}
    				}
    			}
			}
        	
        }
        return false;
	}
	/**
	 * 获取Fdfs文件
	 * @param groupName
	 * @param storageId
	 * @return
	 */
	private byte[] downloadFdfsFile(String groupName,String storageId){
		byte[] b=null;
		try {
			StorageServer storageServer = null;
            TrackerServer trackerServer = trackerClient.getConnection(); 
            try {
            	

                StorageClient storageClient = new StorageClient(trackerServer, 
                        storageServer); 
                b = storageClient.download_file(groupName,storageId); 
               
			} finally {
				if(storageServer != null)
					 storageServer.close();
				trackerServer.close();
			}
            
            
        } catch (Exception e) { 
            e.printStackTrace(); 
        } 
		return b;
	}
	private boolean mulityFileSaveFdfs(List<FastDFSFile> fileList,String userId){
		try {
			if (fileList.size() < 0 ) {
				return false;
			}
			TrackerServer trackerServer = null;
			StorageClient storageClient;
			StorageServer storageServer = null;
			try {
				 trackerServer = trackerClient.getConnection();
				 storageClient = new StorageClient(trackerServer, storageServer);
				 
				if(trackerServer==null || storageClient==null){
					logger.error("TrackerServer can not connect!");
					return false;
				}
				
				List<com.zimmur.model.fdfs.StorageFiles> storageFiles = new ArrayList<StorageFiles>();
				
				for (FastDFSFile fastDFSFile : fileList) {
					if (!StringUtils.isEmpty(fastDFSFile.getExt())) {
						NameValuePair nvp[] = new NameValuePair[] { new NameValuePair(AUTHOR, userId),
								new NameValuePair(FILE_NAME, fastDFSFile.getName()) };
						try {
							String[] uploadResults = storageClient.upload_file(fastDFSFile.getContent(), fastDFSFile.getExt(), nvp);
							if(uploadResults != null){
								String groupName = uploadResults[0];
								String remoteFileName = uploadResults[1];						
								
								com.zimmur.model.fdfs.StorageFiles storageFile = new StorageFiles();
								InputStream inputStream = null;
								try {									
									inputStream = new ByteArrayInputStream(fastDFSFile.getContent());
									BufferedImage bufferedImage= ImageIO.read(inputStream);
									if(bufferedImage != null){
										storageFile.setWidth(bufferedImage.getWidth());
										storageFile.setHeight(bufferedImage.getHeight());
									}									
									inputStream.close();
								} catch (Exception e) {
									logger.error(e.getMessage());
								}finally{
									if(inputStream != null)
										inputStream.close();
								}
								storageFile.setFiletype(ConstData.STORAGE_FILE_TYPE_PRODUCT);
								storageFile.setOriginalfilename(fastDFSFile.getName());
								storageFile.setFilesize(fastDFSFile.getSize());
								storageFile.setAuthor(userId);
								storageFile.setFileext(fastDFSFile.getExt());
								storageFile.setStoragegroup(groupName);
								storageFile.setStorageid(remoteFileName);
								storageFile.setCreatedate(DateUtils.getNowUnixTime());
								storageFiles.add(storageFile);
							}
						} catch (Exception e) {
							logger.error(e.getMessage());
						}
						
					}
				}
				if(storageFiles.size()>0 && saveStorageToDb(storageFiles)){
					for (int i=0;i<fileList.size();i++) {
						fileList.get(i).setSaveId(storageFiles.get(i).getFileid().toString());
					}
				}
			} catch (IOException e) {
				logger.error(e.getMessage());
				return false;
			}finally{
				if(trackerServer != null)
					trackerServer.close();
			}
			
		}catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
		return true;
	}
	
	private StorageFiles getStorageFile(long fileId){
		return storageFilesService.selectByFileId(fileId);
	}
	/**
	 * 保存上传数据信息
	 * @param files
	 * @return
	 */
	private boolean saveStorageToDb(List<com.zimmur.model.fdfs.StorageFiles> files){
		boolean bRet = true;
		try {
			for (StorageFiles storageFiles : files) {
				storageFiles.setFileid(IDWorkFactory.getID(AppModuleEnum.Global));
				storageFilesService.insert(storageFiles);
			}			
		} catch (Exception e) {
			bRet=false;
		}
		return bRet;
	}
}
